######################################################################
# Time-stamp: <05/08/09 17:02:47 ostolop>
#
# Routines to validate BGA queries
######################################################################
package EP::EPC::Interface::Validator::Between_Group_Analysis;
use strict;

use EP::Config;

use EP::Common;
use EP::Common::DB;
use EP::Common::General;
use EP::Common::Error qw ( :try );

use Carp;

=head1 NAME

QueryValidator::Between_Group_Analysis

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 METHODS

=over

=back

=cut

my $COMPID = 6;

sub new {
  my $proto = shift;
  my $class = ref($proto) || $proto;
  my $self  = {};
  bless $self, $class;
  return $self;
}

sub validate {
  my $self = shift;
  my ($component, $source) = @_;

# TODO: disabled class vector format validation - need to figure out how to obtain source dataset properly at this stage
  my $err_code;# = check_class_vector_format ( $component, $source );

  return $err_code;
}

sub check_class_vector_format {
  my ($component, $source) = @_;

  my $src_dataset_id;

  my $cur_act_id = $component->findvalue ( './/submit[starts-with(@name, "current_action_id")]/value' );
  if ( $cur_act_id ) {
    $src_dataset_id = EP::Common::DB::get_action_dst_dataset ( $cur_act_id );
  } else {
    $src_dataset_id = $component->findvalue ( './/submit[starts-with(@name, "current_root_dataset_id")]/value' );
  }

  if ( !$src_dataset_id ) {
    return "No source dataset was found!";
  }

  my $long_class_vector  = $component->find ('section[@id=1]/subsection[@id=0]/submit[@name=\'classvec___c_6_s_1_su_0\']/value')->pop();
  my $short_class_vector = $component->find ('section[@id=1]/subsection[@id=0]/submit[@name=\'classvec_short___c_6_s_1_su_0\']/value')->pop();

  if ( not (defined $long_class_vector or defined $short_class_vector ) ) {
    return "You need to supply a class vector!"
  }

  my $metadata = EP::Common::DB::get_dataset_metadata_as_hash ( $src_dataset_id, "exp" );
  my $nr_of_classes;

  if ( defined $long_class_vector ) {
    my $long_class_vector_txt = $long_class_vector->textContent;
    my @classes = split /\s/, $long_class_vector_txt;
    $nr_of_classes = scalar @classes;
  } else {
    my $short_class_vector_txt = $short_class_vector->textContent;

    my %classes;
    my @class_defs = split /;/, $short_class_vector_txt;

    foreach (@class_defs) {
      my ( $range, $label ) = split /:/;
      return "Couldn't format class vector shorthand - label missing!" if not $label;

      my ( $range_from, $range_to ) = split /-/, $range;

      return "First range limit ($range_from) invalid for class '$label'!" if $range_from !~ /^\d+$/;
      return "Second range limit ($range_to) invalid for class '$label'!" if defined $range_to && $range_to !~ /^\d+$/;

      push @{$classes{$label}}, [$range_from, defined $range_to ? $range_to : $range_from ];
    }

    my @classvec_array;
    foreach my $label ( keys %classes ) {
      foreach my $range_def ( @{$classes{$label}} ) {
	my ($from, $to) = ($$range_def[0] - 1, $$range_def[1] - 1);
	
	for ($from..$to) {
	  if ( defined $classvec_array[$_] ) {
	    return "Overlapping ranges: sample ".($_+1)." belongs to both $classvec_array[$_] and '$label'!";
	  } else {
	    $classvec_array[$_] = "'$label'";
	  }
	}
      }
    }

    my $unmapped_samples = grep /^$/, @classvec_array;
    if ( $unmapped_samples ) {
      return "Incontiguous ranges defined! $unmapped_samples samples are unmapped.";
    }

    my $classvec_long = join (",", @classvec_array);
    print STDERR "[BGA VALIDATE] ", scalar @classvec_array, " $classvec_long\n";
    $nr_of_classes = scalar @classvec_array;
  }

  if ( $nr_of_classes != $metadata->{num_columns} ) {
    return "Number of classes ($nr_of_classes) must match number of columns ($metadata->{num_columns})!";
  }

  print STDERR "[BGA VALIDATOR] ", $metadata->{num_columns}, $short_class_vector->textContent(), "\n";
  return;
}

1;

